﻿/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Cobalt.Framework.UI
{

	public enum VirtualButton
	{
		Left, Right, Up, Down,
		A, B, X, Y,
		Start, Back,
	}

	/// <summary>
	/// Routed to indicate a virtual button "press".
	/// </summary>
	public class VirtualButtonEvent : Event
	{
		public VirtualButton Button { get; set; }
	}

	public enum GamePadButton
	{
		A, B, X, Y,
		DPadUp, DPadLeft, DPadDown, DPadRight,
		Back, Start,
		LB, RB,
		LeftStick, RightStick,
	}

	public class GamePadEvent : Event
	{
		public PlayerIndex PlayerIndex { get; set; }
	}

	/// <summary>
	/// Routed when a game pad button's state changes.
	/// </summary>
	public class GamePadButtonEvent : GamePadEvent
	{
		public GamePadButton Button { get; set; }
		public bool IsDown { get; set; }
	}

	public class GamePadInput : InputProvider
	{
		private PlayerIndex index;
		public PlayerIndex Index { get { return index; } }

		public GamePadInput( PlayerIndex index )
		{
			this.index = index;
		}

		private bool isFirstTick = true;
		private GamePadState prevState;

		public override void Tick()
		{
			var state = GamePad.GetState( index );

			if( isFirstTick )
			{
				prevState = state;
				isFirstTick = false;
			}

			if( state.PacketNumber != prevState.PacketNumber )
			{
				if( state.Buttons.A != prevState.Buttons.A )
					RaiseButtonEvent( GamePadButton.A, state.Buttons.A == ButtonState.Pressed );

				if( state.Buttons.B != prevState.Buttons.B )
					RaiseButtonEvent( GamePadButton.B, state.Buttons.B == ButtonState.Pressed );

				if( state.Buttons.X != prevState.Buttons.X )
					RaiseButtonEvent( GamePadButton.X, state.Buttons.X == ButtonState.Pressed );

				if( state.Buttons.Y != prevState.Buttons.Y )
					RaiseButtonEvent( GamePadButton.Y, state.Buttons.Y == ButtonState.Pressed );

				if( state.Buttons.LeftShoulder != prevState.Buttons.LeftShoulder )
					RaiseButtonEvent( GamePadButton.LB, state.Buttons.LeftShoulder == ButtonState.Pressed );

				if( state.Buttons.RightShoulder != prevState.Buttons.RightShoulder )
					RaiseButtonEvent( GamePadButton.RB, state.Buttons.RightShoulder == ButtonState.Pressed );

				if( state.Buttons.Back != prevState.Buttons.Back )
					RaiseButtonEvent( GamePadButton.Back, state.Buttons.Back == ButtonState.Pressed );

				if( state.Buttons.Start != prevState.Buttons.Start )
					RaiseButtonEvent( GamePadButton.Start, state.Buttons.Start == ButtonState.Pressed );

				if( state.Buttons.LeftStick != prevState.Buttons.LeftStick )
					RaiseButtonEvent( GamePadButton.LeftStick, state.Buttons.LeftStick == ButtonState.Pressed );

				if( state.Buttons.RightStick != prevState.Buttons.RightStick )
					RaiseButtonEvent( GamePadButton.RightStick, state.Buttons.RightStick == ButtonState.Pressed );

				if( state.DPad.Left != prevState.DPad.Left )
					RaiseButtonEvent( GamePadButton.DPadLeft, state.DPad.Left == ButtonState.Pressed );

				if( state.DPad.Right != prevState.DPad.Right )
					RaiseButtonEvent( GamePadButton.DPadRight, state.DPad.Right == ButtonState.Pressed );

				if( state.DPad.Up != prevState.DPad.Up )
					RaiseButtonEvent( GamePadButton.DPadUp, state.DPad.Up == ButtonState.Pressed );

				if( state.DPad.Down != prevState.DPad.Down )
					RaiseButtonEvent( GamePadButton.DPadDown, state.DPad.Down == ButtonState.Pressed );

				prevState = state;
			}
		}

		GamePadButtonEvent gameButtonEv = new GamePadButtonEvent();
		VirtualButtonEvent virtualButtonEv = new VirtualButtonEvent();

		private void RaiseButtonEvent( GamePadButton button, bool down )
		{
			gameButtonEv.PlayerIndex = index;
			gameButtonEv.Button = button;
			gameButtonEv.IsDown = down;

			Owner.Route( gameButtonEv, Owner.FocusedPath );

			if( !down )
			{
				switch( button )
				{
				case GamePadButton.A:
					RaiseVirtualButtonEvent( VirtualButton.A );
					break;

				case GamePadButton.B:
					RaiseVirtualButtonEvent( VirtualButton.B );
					break;

				case GamePadButton.X:
					RaiseVirtualButtonEvent( VirtualButton.X );
					break;

				case GamePadButton.Y:
					RaiseVirtualButtonEvent( VirtualButton.Y );
					break;

				case GamePadButton.DPadLeft:
					RaiseVirtualButtonEvent( VirtualButton.Left );
					break;

				case GamePadButton.DPadRight:
					RaiseVirtualButtonEvent( VirtualButton.Right );
					break;

				case GamePadButton.DPadUp:
					RaiseVirtualButtonEvent( VirtualButton.Up );
					break;

				case GamePadButton.DPadDown:
					RaiseVirtualButtonEvent( VirtualButton.Down );
					break;

				case GamePadButton.Start:
					RaiseVirtualButtonEvent( VirtualButton.Start );
					break;

				case GamePadButton.Back:
					RaiseVirtualButtonEvent( VirtualButton.Back );
					break;
				}
			}
		}

		private void RaiseVirtualButtonEvent( VirtualButton button )
		{
			virtualButtonEv.Button = button;
			Owner.Route( virtualButtonEv, Owner.FocusedPath );
		}
	}

}